#include "gt9147.h"
#include "ctiic.h"
#include "usart.h"
#include "string.h"
#include "nt35510.h"
#include <stdio.h>
#include "main.h"

GT9147_Info parm = {0};

const uint16_t POINT_COLOR_TBL[GT9147_MAX_TOUCH] = {RED, GREEN, BLUE, BROWN, GRED};

const uint8_t GT9147_CFG_TBL[] =
		{
				0X60,
				0XE0,
				0X01,
				0X20,
				0X03,
				0X05,
				0X35,
				0X00,
				0X02,
				0X08,
				0X1E,
				0X08,
				0X50,
				0X3C,
				0X0F,
				0X05,
				0X00,
				0X00,
				0XFF,
				0X67,
				0X50,
				0X00,
				0X00,
				0X18,
				0X1A,
				0X1E,
				0X14,
				0X89,
				0X28,
				0X0A,
				0X30,
				0X2E,
				0XBB,
				0X0A,
				0X03,
				0X00,
				0X00,
				0X02,
				0X33,
				0X1D,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X32,
				0X00,
				0X00,
				0X2A,
				0X1C,
				0X5A,
				0X94,
				0XC5,
				0X02,
				0X07,
				0X00,
				0X00,
				0X00,
				0XB5,
				0X1F,
				0X00,
				0X90,
				0X28,
				0X00,
				0X77,
				0X32,
				0X00,
				0X62,
				0X3F,
				0X00,
				0X52,
				0X50,
				0X00,
				0X52,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X0F,
				0X0F,
				0X03,
				0X06,
				0X10,
				0X42,
				0XF8,
				0X0F,
				0X14,
				0X00,
				0X00,
				0X00,
				0X00,
				0X1A,
				0X18,
				0X16,
				0X14,
				0X12,
				0X10,
				0X0E,
				0X0C,
				0X0A,
				0X08,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X29,
				0X28,
				0X24,
				0X22,
				0X20,
				0X1F,
				0X1E,
				0X1D,
				0X0E,
				0X0C,
				0X0A,
				0X08,
				0X06,
				0X05,
				0X04,
				0X02,
				0X00,
				0XFF,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0X00,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
				0XFF,
};
//发送GT9147配置参数
//mode:0,参数不保存到flash
//     1,参数保存到flash
uint8_t GT9147_Send_Cfg(uint8_t mode)
{
	uint8_t buf[2];
	uint8_t i = 0;
	buf[0] = 0;
	buf[1] = mode; //是否写入到GT9147 FLASH?  即是否掉电保存
	for (i = 0; i < sizeof(GT9147_CFG_TBL); i++)
	{
		buf[0] += GT9147_CFG_TBL[i]; //计算校验和
	}
	buf[0] = (~buf[0]) + 1;
	GT9147_WR_Reg(GT_CFGS_REG, (uint8_t *)GT9147_CFG_TBL, sizeof(GT9147_CFG_TBL)); //发送寄存器配置
	GT9147_WR_Reg(GT_CHECK_REG, buf, 2);																					 //写入校验和,和配置更新标记
	return 0;
}
//向GT9147写入一次数据
//reg:起始寄存器地址
//buf:数据缓缓存区
//len:写数据长度
//返回值:0,成功;1,失败.
uint8_t GT9147_WR_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
	uint8_t i;
	uint8_t ret = 0;
	CT_IIC_Start();
	CT_IIC_Send_Byte(GT_CMD_WR); //发送写命令
	CT_IIC_Wait_Ack();
	CT_IIC_Send_Byte(reg >> 8); //发送高8位地址
	CT_IIC_Wait_Ack();
	CT_IIC_Send_Byte(reg & 0XFF); //发送低8位地址
	CT_IIC_Wait_Ack();
	for (i = 0; i < len; i++)
	{
		CT_IIC_Send_Byte(buf[i]); //发数据
		ret = CT_IIC_Wait_Ack();
		if (ret)
			break;
	}
	CT_IIC_Stop(); //产生一个停止条件
	return ret;
}
//从GT9147读出一次数据
//reg:起始寄存器地址
//buf:数据缓缓存区
//len:读数据长度
void GT9147_RD_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
	uint8_t i;
	CT_IIC_Start();
	CT_IIC_Send_Byte(GT_CMD_WR); //发送写命令
	CT_IIC_Wait_Ack();
	CT_IIC_Send_Byte(reg >> 8); //发送高8位地址
	CT_IIC_Wait_Ack();
	CT_IIC_Send_Byte(reg & 0XFF); //发送低8位地址
	CT_IIC_Wait_Ack();
	CT_IIC_Start();
	CT_IIC_Send_Byte(GT_CMD_RD); //发送读命令
	CT_IIC_Wait_Ack();
	for (i = 0; i < len; i++)
	{
		buf[i] = CT_IIC_Read_Byte(i == (len - 1) ? 0 : 1); //发数据
	}
	CT_IIC_Stop(); //产生一个停止条件
}
//初始化GT9147触摸屏
//返回值:0,初始化成功;1,初始化失败
uint8_t GT9147_Init(void)
{
	uint8_t temp[5];
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); //使能PF端口时钟

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;			 // PF11端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOF, &GPIO_InitStructure); //PF11推挽输出
	GPIO_SetBits(GPIOF, GPIO_Pin_1);			 //上拉

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;		// PB2端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
	GPIO_Init(GPIOF, &GPIO_InitStructure);				//PF10上拉输入
	GPIO_SetBits(GPIOF, GPIO_Pin_10);							//上拉

	CT_IIC_Init(); //初始化电容屏的I2C总线
	GT_RST = 0;		 //复位
	Delay_Ms(10);
	GT_RST = 1; //释放复位
	Delay_Ms(10);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;		// PB2端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
	GPIO_Init(GPIOF, &GPIO_InitStructure);				//PF10下拉输入
	GPIO_ResetBits(GPIOF, GPIO_Pin_10);						//下拉

	Delay_Ms(100);
	GT9147_RD_Reg(GT_PID_REG, temp, 4); //读取产品ID
	temp[4] = 0;
	printf("CTP ID: %s\r\n", temp);				 //打印ID
	if (strcmp((char *)temp, "9147") == 0) //ID==9147
	{
		temp[0] = 0X02;
		GT9147_WR_Reg(GT_CTRL_REG, temp, 1); //软复位GT9147
		GT9147_RD_Reg(GT_CFGS_REG, temp, 1); //读取GT_CFGS_REG寄存器
		if (temp[0] < 0X60)									 //默认版本比较低,需要更新flash配置
		{
			printf("Default Ver:%d\r\n", temp[0]);
			GT9147_Send_Cfg(1); //更新并保存配置
		}
		Delay_Ms(10);
		temp[0] = 0X00;
		GT9147_WR_Reg(GT_CTRL_REG, temp, 1); //结束复位
		parm.touchtype |= 0X80;							 //电容屏
		parm.touchtype |= info.dir & 0X01;	 //横屏还是竖屏
		return 0;
	}
	return 1;
}
const uint16_t GT9147_TPX_TBL[5] = {GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG};
//扫描触摸屏(采用查询方式)
//mode:0,正常扫描.
//返回值:当前触屏状态.
//0,触屏无触摸;1,触屏有触摸
uint8_t GT9147_Scan(uint8_t mode)
{
	uint8_t buf[4];
	uint8_t i = 0;
	uint8_t res = 0;
	uint8_t temp;
	uint8_t tempsta;
	static uint8_t t = 0; //控制查询间隔,从而降低CPU占用率
	t++;
	if ((t % 10) == 0 || t < 10) //空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率
	{
		GT9147_RD_Reg(GT_GSTID_REG, &mode, 1); //读取触摸点的状态
		if (mode & 0X80 && ((mode & 0XF) < 6))
		{
			temp = 0;
			GT9147_WR_Reg(GT_GSTID_REG, &temp, 1); //清标志
		}
		if ((mode & 0XF) && ((mode & 0XF) < 6))
		{
			temp = 0XFF << (mode & 0XF); //将点的个数转换为1的位数,匹配parm.status定义
			tempsta = parm.status;			 //保存当前的parm.status值
			parm.status = (~temp) | GT9147_PRES_DOWN | GT9147_CATH_PRES;
			parm.x[4] = parm.x[0]; //保存触点0的数据
			parm.y[4] = parm.y[0];
			for (i = 0; i < 5; i++)
			{
				if (parm.status & (1 << i)) //触摸有效?
				{
					GT9147_RD_Reg(GT9147_TPX_TBL[i], buf, 4); //读取XY坐标值
					if (parm.touchtype & 0X01)								//横屏
					{
						parm.y[i] = ((uint16_t)buf[1] << 8) + buf[0];
						parm.x[i] = 800 - (((uint16_t)buf[3] << 8) + buf[2]);
					}
					else
					{
						parm.x[i] = ((uint16_t)buf[1] << 8) + buf[0];
						parm.y[i] = ((uint16_t)buf[3] << 8) + buf[2];
					}
					//printf("x[%d]:%d,y[%d]:%d\r\n",i,parm.x[i],i,parm.y[i]);
				}
			}
			res = 1;
			if (parm.x[0] > info.width || parm.y[0] > info.height) //非法数据(坐标超出了)
			{
				if ((mode & 0XF) > 1) //有其他点有数据,则复第二个触点的数据到第一个触点.
				{
					parm.x[0] = parm.x[1];
					parm.y[0] = parm.y[1];
					t = 0; //触发一次,则会最少连续监测10次,从而提高命中率
				}
				else //非法数据,则忽略此次数据(还原原来的)
				{
					parm.x[0] = parm.x[4];
					parm.y[0] = parm.y[4];
					mode = 0X80;
					parm.status = tempsta; //恢复parm.status
				}
			}
			else
			{
				t = 0; //触发一次,则会最少连续监测10次,从而提高命中率
			}
		}
	}
	if ((mode & 0X8F) == 0X80) //无触摸点按下
	{
		if (parm.status & GT9147_PRES_DOWN) //之前是被按下的
		{
			parm.status &= ~(1 << 7); //标记按键松开
		}
		else //之前就没有被按下
		{
			parm.x[0] = 0xffff;
			parm.y[0] = 0xffff;
			parm.status &= 0XE0; //清除点有效标记
		}
	}
	if (t > 240)
	{
		t = 10; //重新从10开始计数
	}
	return res;
}

void ctp_test(void)
{
	u8 t = 0;
	u8 i = 0;
	uint16_t lastpos[5][2];
	while (1)
	{
		GT9147_Scan(0);
		for (t = 0; t < GT9147_MAX_TOUCH; t++)
		{
			if ((parm.status) & (1 << t))
			{
				if (parm.x[t] < info.width && parm.y[t] < info.height)
				{
					if (lastpos[t][0] == 0XFFFF)
					{
						lastpos[t][0] = parm.x[t];
						lastpos[t][1] = parm.y[t];
					}
					lcd_draw_bline(lastpos[t][0], lastpos[t][1], parm.x[t], parm.y[t], 2, POINT_COLOR_TBL[t]);
					lastpos[t][0] = parm.x[t];
					lastpos[t][1] = parm.y[t];
					if (parm.x[t] > (info.width - 24) && parm.y[t] < 16)
					{
						Load_Drow_Dialog();
					}
				}
			}
			else
			{
				lastpos[t][0] = 0XFFFF;
			}
		}
		Delay_Ms(5);
		i++;
	}
}

void Load_Drow_Dialog(void)
{
	NT35510_Clear(WHITE);
	POINT_COLOR = BLUE;
	NT35510_ShowString(info.width - 24, 0, 200, 16, 16, (uint8_t*)"RST");
	POINT_COLOR = RED;
}

void lcd_draw_bline(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, u8 size, uint16_t color)
{
	uint16_t t;
	int xerr = 0, yerr = 0, delta_x, delta_y, distance;
	int incx, incy, uRow, uCol;
	if (x1 < size || x2 < size || y1 < size || y2 < size)
	{
		return;
	}
	delta_x = x2 - x1;
	delta_y = y2 - y1;
	uRow = x1;
	uCol = y1;
	if (delta_x > 0)
	{
		incx = 1;
	}
	else if (delta_x == 0)
	{
		incx = 0;
	}
	else
	{
		incx = -1;
		delta_x = -delta_x;
	}
	if (delta_y > 0)
	{
		incy = 1;
	}
	else if (delta_y == 0)
	{
		incy = 0;
	}
	else
	{
		incy = -1;
		delta_y = -delta_y;
	}
	if (delta_x > delta_y)
	{
		distance = delta_x;
	}
	else
	{
		distance = delta_y;
	}
	for (t = 0; t <= distance + 1; t++)
	{
		gui_fill_circle(uRow, uCol, size, color);
		xerr += delta_x;
		yerr += delta_y;
		if (xerr > distance)
		{
			xerr -= distance;
			uRow += incx;
		}
		if (yerr > distance)
		{
			yerr -= distance;
			uCol += incy;
		}
	}
}

void gui_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color)
{
	u32 i;
	u32 imax = ((u32)r * 707) / 1000 + 1;
	u32 sqmax = (u32)r * (u32)r + (u32)r / 2;
	u32 x = r;
	gui_draw_hline(x0 - r, y0, 2 * r, color);
	for (i = 1; i <= imax; i++)
	{
		if ((i * i + x * x) > sqmax) // draw lines from outside
		{
			if (x > imax)
			{
				gui_draw_hline(x0 - i + 1, y0 + x, 2 * (i - 1), color);
				gui_draw_hline(x0 - i + 1, y0 - x, 2 * (i - 1), color);
			}
			x--;
		}
		gui_draw_hline(x0 - x, y0 + i, 2 * x, color);
		gui_draw_hline(x0 - x, y0 - i, 2 * x, color);
	}
}

void gui_draw_hline(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color)
{
	if (len == 0){
		return;
	}
	NT35510_Fill(x0, y0, x0 + len - 1, y0, color);
}